package com.gulimall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.gulimall.common.constant.ProductConstant;
import com.gulimall.common.utils.R;
import com.gulimall.product.dao.AttrAttrgroupRelationDao;
import com.gulimall.product.dao.AttrGroupDao;
import com.gulimall.product.dao.CategoryDao;
import com.gulimall.product.entity.AttrAttrgroupRelationEntity;
import com.gulimall.product.entity.AttrGroupEntity;
import com.gulimall.product.entity.CategoryEntity;
import com.gulimall.product.resp.AttrRespVo;
import com.gulimall.product.service.AttrAttrgroupRelationService;
import com.gulimall.product.service.CategoryService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gulimall.common.utils.PageUtils;
import com.gulimall.common.utils.Query;

import com.gulimall.product.dao.AttrDao;
import com.gulimall.product.entity.AttrEntity;
import com.gulimall.product.service.AttrService;
import org.springframework.transaction.annotation.Transactional;


@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {
    @Autowired
    private CategoryDao categoryDao;
    @Autowired
    private AttrGroupDao attrGroupDao;
    @Autowired
    private AttrAttrgroupRelationDao attrAttrgroupRelationDao;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private AttrAttrgroupRelationService attrAttrgroupRelationService;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                new QueryWrapper<AttrEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryAttrList(Map<String, Object> params, Long catelogId, String attrType) {
        QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>() {{
            //拼接查询条件，如果属性类型为base就查询基本属性的类型
            eq("attr_type", "base".equalsIgnoreCase(attrType) ? ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() : ProductConstant.AttrEnum.ATTR_TYPE_SALE.getCode());
        }};

        //如果为0查询全部
        if (!catelogId.equals(0L)) {
            queryWrapper.eq("catelog_id", catelogId);
        }
        //属性名称的模糊查询
        String key = (String) params.get("key");
        if (StringUtils.isNotEmpty(key)) {
            queryWrapper.like("attr_name", key);
        }

        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    /**
     * 用于同步数据
     *
     * @param attrGroupId
     * @param attrGroupName
     */
    @Override
    public void updateAttrGroup(Long attrGroupId, String attrGroupName) {
        AttrEntity attrEntity = new AttrEntity();
        attrEntity.setAttrGroupId(attrGroupId);
        attrEntity.setAttrGroupName(attrGroupName);
        UpdateWrapper<AttrEntity> updateWrapper = new UpdateWrapper<AttrEntity>().eq("attr_group_id", attrGroupId);

        this.update(attrEntity, updateWrapper);
    }

    /**
     * 用于同步数据
     *
     * @param catId
     * @param name
     */
    @Override
    public void updateCategory(Long catId, String name) {
        AttrEntity attrEntity = new AttrEntity();
        attrEntity.setCatelogId(catId);
        attrEntity.setCatelogName(name);
        UpdateWrapper<AttrEntity> updateWrapper = new UpdateWrapper<AttrEntity>().eq("catelog_id", catId);

        this.update(attrEntity, updateWrapper);
    }

    /**
     * 根据属性id查询详细信息
     *
     * @param attrId
     * @return
     */
    @Override
    public AttrRespVo getAttrInfo(Long attrId) {
        //根据属性id查询详细信息
        AttrEntity attrEntity = this.getById(attrId);

        //创建attr的resp对象，将其他的属性存入到其中
        AttrRespVo attrRespVo = new AttrRespVo();
        //将一致的属性进行copy
        BeanUtils.copyProperties(attrEntity, attrRespVo);

        //查询分类信息catelogPath
        Long catelogId = attrEntity.getCatelogId();
        Long[] catelogPath = categoryService.findCatelogPath(catelogId);
        attrRespVo.setCatelogPath(catelogPath);

        return attrRespVo;
    }

    /**
     * 修改，需要先获取分类和分组的名称，一起同步数据到数据库
     * 其次需要修改中间表attr_attrgroup_relation的数据
     *
     * @param attr
     */
    @Transactional
    @Override
    public void updateAttr(AttrEntity attr) {
        //获取分类名称 分组名称
        if (attr.getCatelogId() != null) {
            CategoryEntity categoryEntity = categoryDao.selectById(attr.getCatelogId());
            attr.setCatelogName(categoryEntity.getName());
        }
        //在属性类型为基本类型的时候进行拼接分组相关信息
        if (attr.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
            if (attr.getAttrGroupId() != null) {
                AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attr.getAttrGroupId());
                attr.setAttrGroupName(attrGroupEntity.getAttrGroupName());
            }
        }

        //修改基本数据
        this.updateById(attr);

        //如果类型为基本类型还需修改关联分组，并判断用户是否选择了分组
        if (attr.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
            //如果修改的时候有分组id，则对关系表中的数据进行修改或新增，如果没有分组id则对关系表中数据根据属性id做删除操作
            if (attr.getAttrGroupId() != null) {
                AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
                relationEntity.setAttrGroupId(attr.getAttrGroupId());
                relationEntity.setAttrId(attr.getAttrId());

                //判断该属性是否关联到了分类，如果有关联,进行修改，否则进行添加操作
                QueryWrapper<AttrAttrgroupRelationEntity> queryWrapper = new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId());
                Integer count = attrAttrgroupRelationDao.selectCount(queryWrapper);
                if (count > 0) {
                    UpdateWrapper<AttrAttrgroupRelationEntity> updateWrapper = new UpdateWrapper<AttrAttrgroupRelationEntity>() {{
                        eq("attr_id", attr.getAttrId());
                    }};
                    attrAttrgroupRelationDao.update(relationEntity, updateWrapper);
                } else {
                    attrAttrgroupRelationDao.insert(relationEntity);
                }
            } else {
                attrAttrgroupRelationDao.delete(
                        new QueryWrapper<AttrAttrgroupRelationEntity>() {{
                            eq("attr_id", attr.getAttrId());
                        }}
                );
            }
        }
    }

    /**
     * 删除属性
     *
     * @param asList
     */
    @Transactional
    @Override
    public void removeAttrByIds(List<Long> asList) {
        //先删除主表数据
        baseMapper.deleteBatchIds(asList);

        // 删除中间表数据
        QueryWrapper<AttrAttrgroupRelationEntity> queryWrapper = new QueryWrapper<AttrAttrgroupRelationEntity>() {{
            in("attr_id", asList);
        }};
        attrAttrgroupRelationDao.delete(queryWrapper);
    }

    /**
     * 属性分组功能的属性关联数据查询接口
     * 方法1：(从中间表中查询)
     * 1.1、根据分组id从中间表中查找该分组下的所有属性
     * 1.2、收集查询到的所有的属性的id集合
     * 1.3、根据收集到的属性id对属性表进行批量查询
     * <p>
     * 方法2：(从属性表中查询)
     * 2.1、从属性表中串行所有关联到此分组id的数据
     *
     * @param attrGroupId
     * @return
     */
    @Override
    public List<AttrEntity> getAttrRelation(Long attrGroupId) {
        List<AttrAttrgroupRelationEntity> relationEntities = attrAttrgroupRelationDao.selectList(
                new QueryWrapper<AttrAttrgroupRelationEntity>() {{
                    eq("attr_group_id", attrGroupId);
                }}
        );

        //收集所有的属性id
        List<Long> attrIds = relationEntities.stream().map((attr) -> {
            return attr.getAttrId();
        }).collect(Collectors.toList());

        //通过收集到的所有属性attrIds查询属性表中的所有信息
        List<AttrEntity> attrEntityList = new ArrayList<>();
        if (attrIds.size() > 0) {
            attrEntityList = this.listByIds(attrIds);
        }

        return attrEntityList;
    }

    /**
     * 获取当前分组下没有关联的所有基本属性
     * 方法1、（根据分类表查所在分类，再查分类下的所有基本属性）
     * 1.1、在分组表中（pms_attr_group）根据当前分组的id获取该分组所关联的分类catelogId
     * 1.2、在属性表中（pms_attr）根据分类id（catelogId）查询该分类下所有的基本属性
     * 1.3、在属性分组表中（pms_attr_group）根据分类id（catelogId）查询该分类下所有的分组并收集所有的分组id
     * 1.4、在属性分组中间表中（pms_attr_attrgroup_relation）获取所有分组下关联的属性id并收集
     * 1.5、在收集到的所有属性信息中将已经关联过的属性根据属性id进行排除，并进行收集过滤后的属性信息
     * <p>
     * 方法2、（根据属性表查询）
     * 2.1、直接在属性表中查询分组id和分组名称为null的基本属性属性（ATTR_TYPE_BASE）
     *
     * @param params
     * @param attrGroupId
     * @return
     */
    @Override
    public PageUtils getNoAttrRelation(Map<String, Object> params, Long attrGroupId) {
        //根据当前属性所在分组查询该组的详细信息 获取该分组所在分类 catelogId
        AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrGroupId);
        Long catelogId = attrGroupEntity.getCatelogId();

        //根据获取到的分类id查询该分类下的所有分组
        List<AttrGroupEntity> attrGroupEntities = attrGroupDao.selectList(
                new QueryWrapper<AttrGroupEntity>() {{
                    eq("catelog_id", catelogId);
                }}
        );

        //收集获取到的所有分组的分组id
        List<Long> attrGroupIds = attrGroupEntities.stream().map(item -> {
            return item.getAttrGroupId();
        }).collect(Collectors.toList());

        //根据获取到的分组ids 去中间表中 获取所有分组已经关联的属性
        List<AttrAttrgroupRelationEntity> relationEntities = attrAttrgroupRelationDao.selectList(
                new QueryWrapper<AttrAttrgroupRelationEntity>() {{
                    in("attr_group_id", attrGroupIds);
                }}
        );

        //收集上面获取到的已经关联过的属性的id集合
        List<Long> attrIds = relationEntities.stream().map(item -> {
            return item.getAttrId();
        }).collect(Collectors.toList());

        //获取属于当前分类的所有 【基本】 属性 并将上面获取到的已经关联过的属性进行排除
        //创建查询的条件，并将属性类型(基本属性)和当前的分类的id拼接到查询条件中
        QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>() {{
            eq("attr_type", ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode())
                    .eq("catelog_id", catelogId);
        }};
        //判断获取到的id集合是否有值或为空 ,有值需要将这些值拼接到要排除的查询条件中
        if (attrIds.size() > 0) {
            queryWrapper.notIn("attr_id", attrIds);
        }
        //判断查询的条件参数是否为空，不为空的话将 -> 列表的模糊查询条件（属性名称）一起拼接到查询条件中
        String key = (String) params.get("key");
        if (StringUtils.isNotEmpty(key)) {
            queryWrapper.like("attr_name", key);
        }

        //根据拼接的条件以及分页查询数据并封装为PageUtils返回
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Transactional
    @Override
    public void saveDetail(AttrEntity attr) {
        //查询分类名称 和 分组名称
        CategoryEntity categoryEntity = categoryDao.selectById(attr.getCatelogId());
        //仅在属性类型为1的时候进行拼接分组相关信息
        if (attr.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
            if (attr.getAttrGroupId() != null) {
                AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attr.getAttrGroupId());
                attr.setAttrGroupName(attrGroupEntity.getAttrGroupName());
            }
        }

        //保存基本数据
        attr.setCatelogName(categoryEntity.getName());
        this.save(attr);

        //如果提交的属性类型为基本属性还需要保存关联表数据
        if (attr.getAttrGroupId() != null) {
            if (attr.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
                AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
                attrAttrgroupRelationEntity.setAttrId(attr.getAttrId());
                attrAttrgroupRelationEntity.setAttrGroupId(attr.getAttrGroupId());
                attrAttrgroupRelationService.save(attrAttrgroupRelationEntity);
            }
        }
    }
}